from sklearn.cluster import KMeans
from sklearn import datasets
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import silhouette_score
from sklearn.exceptions import ConvergenceWarning
import warnings
import matplotlib as mpl

# 解决中文显示问题 - 使用支持中文的字体
try:
    # Windows 系统使用微软雅黑
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
    # MacOS 系统使用苹方字体
    # plt.rcParams['font.sans-serif'] = ['PingFang HK']
except:
    # 如果找不到指定字体，尝试使用系统默认支持中文的字体
    plt.rcParams['font.sans-serif'] = ['SimHei', 'Heiti TC', 'STHeiti']

# 解决负号显示问题
plt.rcParams['axes.unicode_minus'] = False

# 错误处理：捕获可能的异常
try:
    # 加载内置的鸢尾花数据集
    iris = datasets.load_iris()
    X = iris.data  # 特征数据（150个样本×4个特征）
    y = iris.target  # 真实标签（0,1,2代表三种鸢尾花）
    feature_names = iris.feature_names  # 特征名称

    # 实验要求1：比较不同初始化方法 ------------------------------
    # 创建图形（15×5英寸大图）
    plt.figure(figsize=(15, 5))

    # 初始化方法列表：k-means++ 和 random
    init_methods = ['k-means++', 'random']
    silhouette_scores = []  # 存储轮廓系数

    # 循环测试两种初始化方法
    for i, method in enumerate(init_methods, 1):
        # 错误处理：捕获KMeans可能产生的收敛警告
        with warnings.catch_warnings():
            warnings.filterwarnings("error", category=ConvergenceWarning)

            try:
                # 实例化KMeans模型
                km = KMeans(n_clusters=3, init=method, n_init=10, random_state=42)

                # 训练模型并预测
                km.fit(X)
                predict = km.predict(X)

                # 计算轮廓系数（实验要求2）
                score = silhouette_score(X, predict)
                silhouette_scores.append(score)

                # 打印聚类中心和轮廓系数
                print(f"\n初始化方法: {method.upper()}")
                print(f"轮廓系数: {score:.4f}")
                print("聚类中心坐标:")
                for center in km.cluster_centers_:
                    print(np.round(center, 2))

                # 绘制当前方法的聚类结果
                plt.subplot(1, 3, i)  # 1行3列的第i个位置
                colors = ['orange', 'green', 'purple']
                col = [colors[label] for label in predict]
                plt.scatter(X[:, 0], X[:, 1], c=col, edgecolor='k', alpha=0.7)
                plt.scatter(km.cluster_centers_[:, 0], km.cluster_centers_[:, 1],
                            c='red', s=200, marker='X', label='聚类中心')
                plt.title(f'KMeans聚类: {method.upper()}\n轮廓系数: {score:.3f}')
                plt.xlabel('花萼长度 (cm)')
                plt.ylabel('花萼宽度 (cm)')
                plt.legend()

            except ConvergenceWarning as cw:
                # 处理收敛警告
                print(f"警告: 方法 {method} - {str(cw)}")
                silhouette_scores.append(float('-inf'))  # 无效分数
            except Exception as e:
                # 捕获其他异常
                print(f"错误: 方法 {method} 执行失败 - {str(e)}")
                silhouette_scores.append(float('-inf'))  # 无效分数

    # 实验要求2：绘制真实标签对比 ------------------------------
    plt.subplot(1, 3, 3)  # 1行3列的第3个位置
    true_colors = ['orange', 'green', 'purple']
    c = [true_colors[label] for label in y]
    plt.scatter(X[:, 0], X[:, 1], c=c, edgecolor='k', alpha=0.7)
    plt.title('真实类别分布')
    plt.xlabel('花萼长度 (cm)')
    plt.ylabel('花萼宽度 (cm)')

    # 显示图形
    plt.tight_layout()
    plt.savefig('kmeans_comparison.png', dpi=300, bbox_inches='tight')  # 保存高清图像
    plt.show()

    # 实验要求2：比较不同方法的轮廓系数
    print("\n===== 聚类效果评估 =====")
    for i, method in enumerate(init_methods):
        print(f"{method.upper()}轮廓系数: {silhouette_scores[i]:.4f}")

    # 确定最佳初始化方法
    best_idx = np.argmax(silhouette_scores)
    print(f"\n最佳初始化方法: {init_methods[best_idx].upper()} (轮廓系数: {silhouette_scores[best_idx]:.4f})")

    # 实验要求3：添加额外错误处理 - 检查数据有效性
    if X.shape[0] == 0:
        raise ValueError("数据集为空，请检查数据加载过程")
    if np.isnan(X).any():
        raise ValueError("数据集中存在NaN值，请进行数据清洗")

except ValueError as ve:
    # 处理特定的值错误
    print(f"数据错误: {str(ve)}")
except Exception as e:
    # 顶层异常处理
    print(f"程序执行出错: {str(e)}")
    import traceback

    traceback.print_exc()  # 打印完整错误栈
finally:
    print("\n程序执行完成")